package com.sky.service.impl;

import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author shh
 * @Date 2025-10-15
 */
@Slf4j
@Service
public class ReportServiceImpl implements ReportService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WorkspaceService workspaceService;
    /**
     * 获取营业额统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {
        //1.准备日期数据dateList
        List<LocalDate> dateList = new ArrayList<>();
        //循环插入日期
        while (!begin.isAfter(end)) {//循环插入日期，直到begin大于end
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        log.info("dateList:{}", dateList);
        //2.准备营业数据turnoverList
        List<Double> turnoverList = new ArrayList<>();
        //营业额为订单已完成的订单金额,并统计每个日期的营业额
        //查询orders表，条件：状态=已完成，下单时间在begin和end之间
        dateList.forEach(date -> {
            Map map = new HashMap<>();
            map.put("status", Orders.COMPLETED);
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Double turnover = orderMapper.selectTurnover(map);
            turnover = turnover == null ? 0.0 : turnover;
            turnoverList.add(turnover);
            //如果turnover为null，设为0.0

        });

        return TurnoverReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))
                .turnoverList(StringUtils.join(turnoverList, ","))//将turnoverList转换为逗号分隔的字符串，举例由[1.0,2.0,3.0]变成"1.0,2.0,3.0"
                .build();
    }

    /**
     * 获取用户统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        //1.准备日期数据dateList
        List<LocalDate> dateList = new ArrayList<>();
        //循环插入日期
        while (!begin.isAfter(end)) {//循环插入日期，直到begin大于end
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        log.info("dateList:{}", dateList);
        //2.准备用户数据userList
        List<Integer> userList = new ArrayList<>();
        //查询user表，统计当日及其之前的所有用户总量，条件：注册时间在begin和end之间
        dateList.forEach(date -> {
            Map map = new HashMap<>();
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer userCount = userMapper.selectAllUserCount(map);
            userCount = userCount == null ? 0 : userCount;
            userList.add(userCount);
        });
        //3.准备新增用户数据newUserList
        List<Integer> newUserList = new ArrayList<>();
        //统计每个日期的新增用户数
        //查询orders表，条件：日期在当天。
        dateList.forEach(date -> {
            Map map = new HashMap<>();
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer newUserCount = userMapper.selectNewUserCount(map);
            newUserCount = newUserCount == null ? 0 : newUserCount;
            newUserList.add(newUserCount);
        });
        return UserReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))
                .totalUserList(StringUtils.join(userList, ","))//将userList转换为逗号分隔的字符串，举例由[1,2,3]变成"1,2,3"
                .newUserList(StringUtils.join(newUserList, ","))//将newUserList转换为逗号分隔的字符串，举例由[1,2,3]变成"1,2,3"
                .build();
    }

    /**
     * 获取订单统计
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        //1.准备日期数据
        List<LocalDate> dateList = new ArrayList<>();
        while (!begin.isAfter(end)) {//循环插入日期，直到begin大于end
            dateList.add(begin);
            begin = begin.plusDays(1);
        }
        log.info("dateList:{}", dateList);
        //2.准备每日订单数据
        List<Integer> orderCountList = new ArrayList<>();
        //查询orders表，统计当日及其之前的所有订单总量，条件：下单时间在begin和end之间
        dateList.forEach(date -> {//遍历dateList，查询每个日期的订单量
            Map map = new HashMap<>();
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));//of方法：创建一个LocalDateTime对象，参数为日期和时间，这里是日期的开始时间
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));//of方法：创建一个LocalDateTime对象，参数为日期和时间，这里是日期的结束时间
            Integer orderCount = orderMapper.countOrderByMap(map);
            orderCount = orderCount == null ? 0 : orderCount;
            orderCountList.add(orderCount);
        });
        //3.准备每日有效订单数据
        List<Integer> newOrderCountList = new ArrayList<>();
        //遍历循环查询每个日期的有效订单数
        //条件：状态=已完成，下单时间在begin和end之间
        dateList.forEach(date -> {
            Map map = new HashMap<>();
            map.put("status", Orders.COMPLETED);
            map.put("beginTime", LocalDateTime.of(date, LocalTime.MIN));
            map.put("endTime", LocalDateTime.of(date, LocalTime.MAX));
            Integer newOrderCount = orderMapper.countOrderByMap(map);
            newOrderCount = newOrderCount == null ? 0 : newOrderCount;
            newOrderCountList.add(newOrderCount);
        });

        //什么是Stream？
        //Stream是Java 8引入的一种新的抽象，用于处理集合（Collection）数据。
        //它可以对集合中的元素进行过滤、映射、排序、聚合等操作，而不需要编写复杂的循环代码。
        //4.订单总数
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).orElse(0);
        //详细解释（用什么方法，什么原理）：用stream的reduce方法，将orderCountList中的所有元素累加起来，初始值为0
        //5.有效订单数
        Integer totalNewOrderCount = newOrderCountList.stream().reduce(Integer::sum).orElse(0);//详细解释：将newOrderCountList中的所有元素累加起来，初始值为0
        //6.订单完成率
        Double orderCompletionRate = totalOrderCount == 0 ? 0.0 : (double) totalNewOrderCount / totalOrderCount;//详细解释：如果totalOrderCount为0，订单完成率为0.0，否则为有效订单数除以订单总数
        //7.封装参数返回
        return OrderReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))
                .orderCountList(StringUtils.join(orderCountList, ","))//将orderCountList转换为逗号分隔的字符串，举例由[1,2,3]变成"1,2,3"
                .validOrderCountList(StringUtils.join(newOrderCountList, ","))//将newOrderCountList转换为逗号分隔的字符串，举例由[1,2,3]变成"1,2,3"
                .totalOrderCount(totalOrderCount)
                .validOrderCount(totalNewOrderCount)
                .orderCompletionRate(orderCompletionRate)
                .build();
    }

    /**
     * 获取top10订单
     *
     * @param begin
     * @param end
     * @return
     */
    @Override
    public SalesTop10ReportVO getTop10Orders(LocalDate begin, LocalDate end) {
        //获取namelist
        //查询orders表，统计当日及其之前的所有订单总量，条件：下单时间在begin和end之间
        List nameList = new ArrayList<>();
        //获取numberlist
        List numberList = new ArrayList<>();
        Map map = new HashMap<>();
        //设置时间为
        map.put("beginTime", LocalDateTime.of(begin, LocalTime.MIN));//of方法：创建一个LocalDateTime对象，参数为日期和时间，这里是日期的开始时间
        map.put("endTime", LocalDateTime.of(end, LocalTime.MAX));//of方法：创建一个LocalDateTime对象，参数为日期和时间，这里是日期的结束时间
        List<Map> mapList = orderMapper.sumTop10(map);
        mapList.forEach(orderMap -> {
            String name = (String) orderMap.get("name");
            nameList.add(name);
            Object number =  orderMap.get("number");
            numberList.add(number);
        });

        return SalesTop10ReportVO.builder()
                .nameList(StringUtils.join(nameList, ","))
                .numberList(StringUtils.join(numberList, ","))
                .build();
    }

        /**
         * 导出订单数据
         * @param response
         */
    @Override
    public void export(HttpServletResponse response) throws IOException {
        //1.查询数据库获取营业数据(30天内)
        LocalDate dateBegin = LocalDate.now().minusDays(30);//30天前的开始时间
        LocalDate dateEnd = LocalDate.now().minusDays(1);//30天前的结束时间
        //LocalDateTiem与LocalDate的区别：LocalDateTiem是日期时间，LocalDate是日期，LocalTime是时间
        //LocalDateTiem可以表示具体的时间点，而LocalDate只能表示日期，LocalTime只能表示时间
        //LocalDateTiem.of方法：创建一个LocalDateTime对象，参数为日期和时间，这里是日期的开始时间和结束时间

        BusinessDataVO businessDataVO = workspaceService.getBusinessData(LocalDateTime.of(dateBegin, LocalTime.MIN), LocalDateTime.of(dateEnd, LocalTime.MAX));
        //2.通过poi将数据写入到excel文件中
        //poi创建步骤：1.创建workbook对象，2.创建sheet对象，3.创建row对象，4.创建cell对象，5.写入数据
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream("F:\\AppCode\\itheimaxm\\xm\\sky-take-out\\sky-server\\src\\main\\resources\\template\\运营数据报表模板.xlsx");
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        XSSFWorkbook workbook = null;
        try {
            workbook = new XSSFWorkbook(fileInputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //填充数据
        XSSFSheet sheet = workbook.getSheetAt(0);//获取第一个sheet页
        sheet.getRow(1).getCell(1).setCellValue("时间"+dateBegin+"至"+dateEnd);//获取第二行

        //获取第4行
        sheet.getRow(3).getCell(2).setCellValue(businessDataVO.getTurnover());
        sheet.getRow(3).getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());
        sheet.getRow(3).getCell(6).setCellValue(businessDataVO.getNewUsers());

        //获取第5行
        sheet.getRow(4).getCell(2).setCellValue(businessDataVO.getUnitPrice());
        sheet.getRow(4).getCell(4).setCellValue(businessDataVO.getNewUsers());

        //填充明细数据（30天内）
        for (int i = 0; i < 30; i++) {
            LocalDate date = dateBegin.plusDays(i);//30天前的第i天
            //查询某一天的营业数据
            BusinessDataVO businessDataVO1 = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
            sheet.getRow(7 + i).getCell(1).setCellValue(date.toString());//填充日期
            sheet.getRow(7 + i).getCell(2).setCellValue(businessDataVO1.getTurnover());//填充营业额
            sheet.getRow(7 + i).getCell(3).setCellValue(businessDataVO1.getValidOrderCount());//填充有效订单数
            sheet.getRow(7 + i).getCell(4).setCellValue(businessDataVO1.getOrderCompletionRate());//填充订单完成率
            sheet.getRow(7 + i).getCell(5).setCellValue(businessDataVO1.getUnitPrice());//填充平均客单价
            sheet.getRow(7 + i).getCell(6).setCellValue(businessDataVO1.getNewUsers());//填充新增用户数
        }


        //3.将excel文件写入到响应体中
        ServletOutputStream outputStream = response.getOutputStream();
        workbook.write(outputStream);
        //4.关闭流
        outputStream.close();
        workbook.close();
    }
}
